-module(measure).

-export(
    [readtest/0, readtest/2,
     writetest/0, writetest/2,
     dummytest/2,
     calltest/2,
     calltest1/0,
     calltest2/0,
     calltest3/0,
     calltest4/0,
     calltest5/0,
     calltest6/0]).
-define(NUM, 60000).
-define(FACTOR, 40).

dummytest(0, _) ->
    ok;
dummytest(N, A) ->
    dummytest(N-1, A).

readtest(0, _) ->
    ok;
readtest(N, Obj) ->
    object:get(Obj, field1),
    object:get(Obj, field2),
    object:get(Obj, field3),
    readtest(N-1, Obj).

writetest(0, _) ->
    ok;
writetest(N, Obj) ->
    object:set(Obj, field1, 7),
    object:set(Obj, field2, 6),
    object:set(Obj, field3, 5),
    readtest(N-1, Obj).

calltest(0, _) ->
    ok;
calltest(N, Obj) ->
    Obj:dummy(), Obj:dummy(), Obj:dummy(), Obj:dummy(), Obj:dummy(),
    Obj:dummy(), Obj:dummy(), Obj:dummy(), Obj:dummy(), Obj:dummy(),
    Obj:dummy(), Obj:dummy(), Obj:dummy(), Obj:dummy(), Obj:dummy(),
    Obj:dummy(), Obj:dummy(), Obj:dummy(), Obj:dummy(), Obj:dummy(),
    Obj:dummy(), Obj:dummy(), Obj:dummy(), Obj:dummy(), Obj:dummy(),
    Obj:dummy(), Obj:dummy(), Obj:dummy(), Obj:dummy(), Obj:dummy(),
    Obj:dummy(), Obj:dummy(), Obj:dummy(), Obj:dummy(), Obj:dummy(),
    Obj:dummy(), Obj:dummy(), Obj:dummy(), Obj:dummy(), Obj:dummy(),
    calltest(N-1, Obj).

test(Name, Fun, Obj, Steps) ->
    {Res1, ok} = timer:tc(?MODULE, dummytest, [Steps, Obj]),
    {Res2, ok} = timer:tc(?MODULE, Fun, [Steps, Obj]),
    Res = Res2 - Res1,
    io:format("~p~nresult:    ~p us~nsteps:     ~p (factor: ~p)~nstep time: ~p us~n", [Name, Res, Steps, ?FACTOR, Res / Steps / ?FACTOR]),
    {Res1, Res2}.

readtest() ->
    test("Field read", readtest, alpha, ?NUM).

writetest() ->
    test("Field write", writetest, alpha, ?NUM).

calltest1() ->
    test("Direct call", calltest, alpha:new(1, 2), ?NUM).

calltest2() ->
    test("Inherited call", calltest, beta:new(1, 2, 3), ?NUM).

calltest3() ->
    test("2x inherited call", calltest, gamma:new(1, 2, 3, 4), ?NUM).

calltest4() ->
    test("3x inherited call", calltest, delta:new(1, 2, 3, 4), ?NUM).

calltest5() ->
    test("4x inherited call", calltest, epsilon:new(1, 2, 3, 4), ?NUM).

calltest6() ->
    test("5x inherited call", calltest, zeta:new(1, 2, 3, 4), ?NUM).